package parser_antlr4.oceanbase_mysql;

import domain.Column;
import domain.Table;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.TerminalNode;
import parser_antlr4.oceanbase_mysql.antlr4.OBMySQLParser;
import parser_antlr4.oceanbase_mysql.antlr4.OBMySQLParserBaseListener;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class OBMySQLListener extends OBMySQLParserBaseListener {

  private CommonTokenStream commonTokenStream;

  public OBMySQLListener(CommonTokenStream commonTokenStream) {
    this.commonTokenStream = commonTokenStream;
  }

  @Getter
  private final List<Table> tableList = new ArrayList<>(10);

  private Table table;
  private List<Column> columnList;

  private List<String> indexSQLList;

  private List<String> foreignKeyList;

  private StringBuilder tableOptions;


  @Override
  public void enterCreate_table_stmt(OBMySQLParser.Create_table_stmtContext ctx) {
    table = new Table();
    columnList = new ArrayList<>();
    indexSQLList = new ArrayList<>();
    foreignKeyList = new ArrayList<>();
    tableOptions = new StringBuilder();

    OBMySQLParser.Relation_factorContext relationFactorContext = ctx.relation_factor();
    table.setTableName(relationFactorContext.getText());
  }

  @Override
  public void enterTable_element(OBMySQLParser.Table_elementContext ctx) {
    OBMySQLParser.Out_of_line_indexContext outOfLineIndexContext = ctx.out_of_line_index();
    if (outOfLineIndexContext != null) {
      parseIndex(outOfLineIndexContext);
    }

    OBMySQLParser.Out_of_line_constraintContext outOfLineConstraintContext = ctx.out_of_line_constraint();
    if (outOfLineConstraintContext != null) {
      parseConstriant(outOfLineConstraintContext);
    }

    OBMySQLParser.Column_definitionContext columnDefinitionContext = ctx.column_definition();
    if (columnDefinitionContext != null) {
      parseColumn(columnDefinitionContext);
    }
  }

  @Override
  public void enterTable_option_list(OBMySQLParser.Table_option_listContext ctx) {
    if (ctx != null) {
      Interval sourceInterval = ctx.getSourceInterval();
      tableOptions.append(getSQLSegment(sourceInterval.a, sourceInterval.b));
    }
  }

  @Override
  public void enterTable_option(OBMySQLParser.Table_optionContext ctx) {
    TerminalNode comment = ctx.COMMENT();
    if (comment != null && ctx.STRING_VALUE() != null) {
      table.setTableComment(ctx.STRING_VALUE().getText());
    }
  }

  private void parseColumn(OBMySQLParser.Column_definitionContext columnCtx) {
    OBMySQLParser.Data_typeContext dataTypeContext = columnCtx.data_type();
    System.out.println(dataTypeContext.getText());
  }

  private void parseIndex(OBMySQLParser.Out_of_line_indexContext outOfLineIndexContext) {
    Interval sourceInterval = outOfLineIndexContext.getSourceInterval();
    String sqlSegment = getSQLSegment(sourceInterval.a, sourceInterval.b);
    indexSQLList.add(sqlSegment);
  }

  private void parseConstriant(OBMySQLParser.Out_of_line_constraintContext outOfLineConstraintContext) {
    Interval sourceInterval = outOfLineConstraintContext.getSourceInterval();
    String sqlSegment = getSQLSegment(sourceInterval.a, sourceInterval.b);
    indexSQLList.add(sqlSegment);
  }

  public String getSQLSegment(Integer start, Integer end) {
    StringBuilder SQL = new StringBuilder();
    List<Token> tokens = commonTokenStream.getTokens(start, end);
    for (Token token : tokens) {
      SQL.append(token.getText());
    }
    return SQL.toString();
  }

  @Override
  public void exitCreate_table_stmt(OBMySQLParser.Create_table_stmtContext ctx) {
    table.setIndexSQLList(indexSQLList);
    table.setForeignKeyList(foreignKeyList);
    table.setTableOptions(tableOptions);
    this.tableList.add(table);
  }
}